#include <jni.h>
#include <string>

extern "C" {
#include "include/libavcodec/avcodec.h"
#include "include/libavformat/avformat.h"
#include "include/libavutil/imgutils.h"
#include "include/libswscale/swscale.h"

#include <libswresample/swresample.h>
}

#include <android/log.h>
#include <android/native_window_jni.h>


#define LOGD(...) __android_log_print(ANDROID_LOG_INFO,"123123",__VA_ARGS__)


extern "C" JNIEXPORT jint
Java_com_yfjin_ffmpeg52_MainActivityAudio_playAudio__Ljava_lang_String_2(JNIEnv *env, jobject thiz, jstring url_) {

    const char *url = env->GetStringUTFChars(url_, 0);

    av_register_all();


    AVFormatContext *pFormatCtx = avformat_alloc_context();

    if (avformat_open_input(&pFormatCtx, url, NULL, NULL) < 0) {
        LOGD("打开文件失败");
        return -1;
    }
    LOGD("打开文件OK");


    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        LOGD("信息读取失败");
        return -1;
    }
    LOGD("信息读取OK");


    int audioIndex = -1;
    for (int i = 0; i < pFormatCtx->nb_streams; ++i) {
        int type = pFormatCtx->streams[i]->codecpar->codec_type;
        if (type == AVMEDIA_TYPE_AUDIO) {
            audioIndex = i;
            break;
        }
    }
    LOGD("audioIndex:%d", audioIndex);

    AVCodecContext *pCodecContext = pFormatCtx->streams[audioIndex]->codec;
    AVCodec *pCodec = avcodec_find_decoder(pCodecContext->codec_id);

    if (avcodec_open2(pCodecContext, pCodec, NULL) < 0) {
        return -1;
    }
    LOGD("avcodec_open2");

    AVPacket *avPacket = (AVPacket *) av_malloc(sizeof(AVPacket));
    AVFrame *avFrame = av_frame_alloc();

    //获取通道数
    int out_channel_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
    LOGD("out_channel:%d", out_channel_nb);



    SwrContext *swrContext = swr_alloc();
    uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
    enum AVSampleFormat out_format = AV_SAMPLE_FMT_S16;
    int out_sample_rate = pCodecContext->sample_rate;
    swr_alloc_set_opts(swrContext, out_channel_layout, out_format, out_sample_rate,
                       pCodecContext->channel_layout, pCodecContext->sample_fmt,
                       pCodecContext->sample_rate, 0, NULL
    );


    int sampleRate=44100;
    int channelNum=2;

    swr_init(swrContext);
    LOGD("swr_init");
    uint8_t *out_buffer = static_cast<uint8_t *>(av_malloc(sampleRate * channelNum));
    jclass player = env->GetObjectClass(thiz);
    jmethodID createAudio = env->GetMethodID(player, "createTrack", "(II)V");
    env->CallVoidMethod(thiz, createAudio, sampleRate, out_channel_nb);
    LOGD("createTrack");
    jmethodID aydio_write = env->GetMethodID(player, "playTrack", "([BI)V");

    while (av_read_frame(pFormatCtx, avPacket) >= 0) {
        if (avPacket->stream_index == audioIndex) {

            LOGD("while audioIndex");


            int ret = avcodec_send_packet(pCodecContext, avPacket);

            if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
                LOGD("解码出错");
                return -1;
            }
            ret = avcodec_receive_frame(pCodecContext, avFrame);
            if (ret == AVERROR(EAGAIN)) {
                continue;
            } else if (ret < 0) {
                break;
            }

            LOGD("while decode");
            //avFrame->data就是具体数据，但是需要通过swr_convert转换成对应码率到out_buffer
            //out_buffer装载数据
            swr_convert(swrContext, &out_buffer, sampleRate * channelNum,
                        (const uint8_t **) (avFrame->data), avFrame->nb_samples);

            int size = av_samples_get_buffer_size(NULL, out_channel_nb, avFrame->nb_samples,
                                                  AV_SAMPLE_FMT_S16, 1);

            jbyteArray audio_sample_array = env->NewByteArray(size);
            //把out_buffer转成java的byte[]数组
            env->SetByteArrayRegion(audio_sample_array, 0, size,
                                    reinterpret_cast<const jbyte *>(out_buffer));

            env->CallVoidMethod(thiz, aydio_write, audio_sample_array, size);
            env->DeleteLocalRef(audio_sample_array);
        }
    }
    av_frame_free(&avFrame);
    av_free(avPacket);
    swr_free(&swrContext);
    avcodec_close(pCodecContext);
    avformat_free_context(pFormatCtx);

    env->ReleaseStringUTFChars(url_, url);
    return 0;
}